/*
 * PROJECT:     ReactOS API tests
 * LICENSE:     MIT (https://spdx.org/licenses/MIT)
 * PURPOSE:     Tests for atan
 * COPYRIGHT:   Copyright 2021 Timo Kreuzer <timo.kreuzer@reactos.org>
 */

#if !defined(_CRTBLD) && !defined(_M_IX86)
#define _CRTBLD // we don't want inline atan!
#endif
#include "math_helpers.h"

#ifdef _MSC_VER
#pragma function(atan)
#endif

#if !defined(_M_IX86)
#define HAS_ATANF
#elif (defined(TEST_UCRTBASE) || defined(TEST_STATIC_CRT))
#define HAS_LIBM_SSE2
#endif


// These are expected to match exactly
static TESTENTRY_DBL s_atan_exact_tests[] =
{
    { 0x0000000000000000 /*  0.000000 */, 0x0000000000000000 /*  0.000000 */ },
    { 0x8000000000000000 /* -0.000000 */, 0x8000000000000000 /* -0.000000 */ },
    { 0x7ff0000000000000 /*  1.#INF00 */, 0x3ff921fb54442d18 /*  1.570796 */ },
    { 0x7ff0000000000001 /*  1.#SNAN0 */, 0x7ff8000000000001 /*  1.#QNAN0 */ },
    { 0x7ff7ffffffffffff /*  1.#SNAN0 */, 0x7fffffffffffffff /*  1.#QNAN0 */ },
    { 0x7ff8000000000000 /*  1.#QNAN0 */, 0x7ff8000000000000 /*  1.#QNAN0 */ },
    { 0x7ff8000000000001 /*  1.#QNAN0 */, 0x7ff8000000000001 /*  1.#QNAN0 */ },
    { 0x7fffffffffffffff /*  1.#QNAN0 */, 0x7fffffffffffffff /*  1.#QNAN0 */ },
    { 0xfff0000000000000 /* -1.#INF00 */, 0xbff921fb54442d18 /* -1.570796 */ },
    { 0xfff0000000000001 /* -1.#SNAN0 */, 0xfff8000000000001 /* -1.#QNAN0 */ },
    { 0xfff7ffffffffffff /* -1.#SNAN0 */, 0xffffffffffffffff /* -1.#QNAN0 */ },
    { 0xfff8000000000000 /* -1.#IND00 */, 0xfff8000000000000 /* -1.#IND00 */ },
    { 0xfff8000000000001 /* -1.#QNAN0 */, 0xfff8000000000001 /* -1.#QNAN0 */ },
    { 0xffffffffffffffff /* -1.#QNAN0 */, 0xffffffffffffffff /* -1.#QNAN0 */ },
};

void Test_atan_exact(void)
{
    for (int i = 0; i < _countof(s_atan_exact_tests); i++)
    {
        double x = u64_to_dbl(s_atan_exact_tests[i].x);
        double z = atan(x);
        ok_eq_dbl_exact("atan", s_atan_exact_tests[i].x, z, s_atan_exact_tests[i].result);
    }
}

// This table is autogenerated by `python gen_math_tests.py atan`
static TESTENTRY_DBL_APPROX s_atan_approx_tests[] =
{
//  {    x,                     {    y_rounded,               y_difference           } }
    {    -0x1.4000000000000p+3, {    -0x1.789bd2c160054p+0,    0x1.f45503ccad255p-54 }, 1 }, // atan(-10.0) == -1.4711276743037345919
    {    -0x1.36e6666666666p+3, {    -0x1.77ddf480c9e24p+0,   -0x1.63ae27540e312p-56 }, 1 }, // atan(-9.715625) == -1.4682305159020723388
    {    -0x1.2dccccccccccdp+3, {    -0x1.7714c2b863662p+0,    0x1.ee183932e374cp-56 }, 1 }, // atan(-9.43125) == -1.4651605320135776277
    {    -0x1.24b3333333333p+3, {    -0x1.763f330b45a94p+0,    0x1.305ceb4f1c1a3p-55 }, 1 }, // atan(-9.146875) == -1.4619018461723145233
    {    -0x1.1b9999999999ap+3, {    -0x1.755c1999720c1p+0,   -0x1.7b6020960849bp-54 }, 1 }, // atan(-8.8625) == -1.4584365844366831967
    {    -0x1.1280000000000p+3, {    -0x1.746a2395437b5p+0,    0x1.331b873ab986dp-55 }, 1 }, // atan(-8.578125) == -1.4547445525563322488
    {    -0x1.0966666666666p+3, {    -0x1.7367d0c4629a5p+0,    0x1.706fbc964d2edp-55 }, 1 }, // atan(-8.29375) == -1.4508028487640356064
    {    -0x1.004cccccccccdp+3, {    -0x1.72536baa136c4p+0,    0x1.2a7481a6be0e3p-56 }, 1 }, // atan(-8.009375) == -1.4465853967880528524
    {    -0x1.ee66666666666p+2, {    -0x1.712b000615001p+0,   -0x1.f230eeee5c692p-59 }, 1 }, // atan(-7.725) == -1.4420623793457709761
    {    -0x1.dc33333333334p+2, {    -0x1.6fec4f3a9cbedp+0,   -0x1.00254d22e470ap-55 }, 1 }, // atan(-7.440625000000001) == -1.4371995466324236912
    {    -0x1.ca00000000000p+2, {    -0x1.6e94c20af4b20p+0,   -0x1.7a0fa624e176cp-56 }, 1 }, // atan(-7.15625) == -1.4319573666331919731
    {    -0x1.b7ccccccccccdp+2, {    -0x1.6d2156f7b7d20p+0,    0x1.78df25ab95b50p-55 }, 1 }, // atan(-6.871875) == -1.4262899737148657255
    {    -0x1.a59999999999ap+2, {    -0x1.6b8e8c40f3152p+0,   -0x1.063fffef8cd8ap-54 }, 1 }, // atan(-6.5875) == -1.420143857819387069
    {    -0x1.9366666666666p+2, {    -0x1.69d84442dfb63p+0,    0x1.635ccdff1d4f9p-57 }, 1 }, // atan(-6.303125) == -1.4134562171236317766
    {    -0x1.8133333333334p+2, {    -0x1.67f9a26d9ceeap+0,   -0x1.ffd66af7f8df4p-54 }, 1 }, // atan(-6.018750000000001) == -1.4061528699502853223
    {    -0x1.6f00000000000p+2, {    -0x1.65ecde7494896p+0,    0x1.25d613afe5c17p-56 }, 1 }, // atan(-5.734375) == -1.3981455835933380545
    {    -0x1.5cccccccccccdp+2, {    -0x1.63ab0a68e6c41p+0,   -0x1.48c8047fed026p-54 }, 1 }, // atan(-5.45) == -1.3893286234004026005
    {    -0x1.4a9999999999ap+2, {    -0x1.612bc7217a32dp+0,   -0x1.06a2ebe1eae7bp-55 }, 1 }, // atan(-5.165625) == -1.3795742470485479477
    {    -0x1.3866666666667p+2, {    -0x1.5e64e066a0c43p+0,    0x1.b3e986aecb5c3p-55 }, 1 }, // atan(-4.8812500000000005) == -1.3687267542416214432
    {    -0x1.2633333333333p+2, {    -0x1.5b49c77c2df72p+0,    0x1.b5547b902084ap-57 }, 1 }, // atan(-4.596875) == -1.3565945318386778299
    {    -0x1.1400000000000p+2, {    -0x1.57cade57dba51p+0,    0x1.8b8666c0ed546p-60 }, 1 }, // atan(-4.3125) == -1.3429392780777968928
    {    -0x1.01ccccccccccdp+2, {    -0x1.53d47f3e77b53p+0,   -0x1.1b59e77a73360p-54 }, 1 }, // atan(-4.028125) == -1.3274611976155100194
    {    -0x1.df33333333334p+1, {    -0x1.4f4da24d136dep+0,   -0x1.20a2f6b2adc5fp-54 }, 1 }, // atan(-3.7437500000000004) == -1.309778350655896491
    {    -0x1.baccccccccccep+1, {    -0x1.4a15f25f022f9p+0,   -0x1.0c557d8094f7dp-56 }, 1 }, // atan(-3.4593750000000005) == -1.2893973810152472715
    {    -0x1.9666666666668p+1, {    -0x1.44030919b8e95p+0,    0x1.5aed17ea1ab46p-55 }, 1 }, // atan(-3.1750000000000007) == -1.2656713187979324499
    {    -0x1.7200000000000p+1, {    -0x1.3cdc609d20e5bp+0,   -0x1.e158a27cb7c2dp-54 }, 1 }, // atan(-2.890625) == -1.2377376922239794399
    {    -0x1.4d9999999999ap+1, {    -0x1.345546e2659b7p+0,    0x1.55f5e08b105c2p-54 }, 1 }, // atan(-2.60625) == -1.2044262221075833588
    {    -0x1.2933333333334p+1, {    -0x1.2a03b5e44c87cp+0,    0x1.49d4bc630ec64p-55 }, 1 }, // atan(-2.3218750000000004) == -1.1641191179628824412
    {    -0x1.04ccccccccccep+1, {    -0x1.1d525880b41bcp+0,    0x1.d286c1bdf6389p-54 }, 1 }, // atan(-2.0375000000000005) == -1.114537745877995155
    {    -0x1.c0cccccccccd0p+0, {    -0x1.0d6b4af89a28cp+0,   -0x1.12ad712947e2fp-59 }, 1 }, // atan(-1.7531250000000007) == -1.0524184090556074641
    {    -0x1.7800000000000p+0, {    -0x1.f232073aeb172p-1,    0x1.5f5b3a2cdfc2cp-55 }, 1 }, // atan(-1.46875) == -0.97303793520181454745
    {    -0x1.2f33333333338p+0, {    -0x1.bd3cd934b6823p-1,    0x1.391d2ab851e2bp-56 }, 1 }, // atan(-1.184375000000001) == -0.86960486191242512523
    {    -0x1.cccccccccccd0p-1, {    -0x1.77338a80603c0p-1,   -0x1.153354d8df079p-56 }, 1 }, // atan(-0.9000000000000004) == -0.73281510178650678792
    {    -0x1.0000000000000p+0, {    -0x1.921fb54442d18p-1,   -0x1.1a62633145c07p-55 }, 1 }, // atan(-1.0) == -0.78539816339744830962
    {    -0x1.e000000000000p-1, {    -0x1.819d0b7158a4dp-1,    0x1.bf76229d3b917p-56 }, 1 }, // atan(-0.9375) == -0.75315128096219438952
    {    -0x1.c000000000000p-1, {    -0x1.700a7c5784634p-1,    0x1.8c34d25aadef6p-56 }, 1 }, // atan(-0.875) == -0.71882999962162450542
    {    -0x1.a000000000000p-1, {    -0x1.5d58987169b18p-1,   -0x1.0028e4bc5e7cap-57 }, 1 }, // atan(-0.8125) == -0.68231655487474807826
    {    -0x1.8000000000000p-1, {    -0x1.4978fa3269ee1p-1,   -0x1.2419a87f2a458p-56 }, 1 }, // atan(-0.75) == -0.6435011087932843868
    {    -0x1.6000000000000p-1, {    -0x1.345f01cce37bbp-1,   -0x1.1021137c71102p-55 }, 1 }, // atan(-0.6875) == -0.60228734613496418168
    {    -0x1.4000000000000p-1, {    -0x1.1e00babdefeb4p-1,    0x1.928df287a668fp-58 }, 1 }, // atan(-0.625) == -0.55859931534356243597
    {    -0x1.2000000000000p-1, {    -0x1.0657e94db30d0p-1,    0x1.d5b495f6349e6p-56 }, 1 }, // atan(-0.5625) == -0.51238946031073770667
    {    -0x1.0000000000000p-1, {    -0x1.dac670561bb4fp-2,   -0x1.a2b7f222f65e2p-56 }, 1 }, // atan(-0.5) == -0.46364760900080611621
    {    -0x1.c000000000000p-2, {    -0x1.a64eec3cc23fdp-2,    0x1.24dec1b50b7ffp-56 }, 1 }, // atan(-0.4375) == -0.4124104415973873069
    {    -0x1.8000000000000p-2, {    -0x1.6f61941e4def1p-2,    0x1.c63aae6f6e918p-56 }, 1 }, // atan(-0.375) == -0.3587706702705722204
    {    -0x1.4000000000000p-2, {    -0x1.362773707ebccp-2,    0x1.963a544b672d8p-57 }, 1 }, // atan(-0.3125) == -0.30288486837497140556
    {    -0x1.0000000000000p-2, {    -0x1.f5b75f92c80ddp-3,   -0x1.8ab6e3cf7afbdp-57 }, 1 }, // atan(-0.25) == -0.24497866312686415417
    {    -0x1.8000000000000p-3, {    -0x1.7b97b4bce5b02p-3,   -0x1.347b0b4f881cap-58 }, 1 }, // atan(-0.1875) == -0.18534794999569476489
    {    -0x1.0000000000000p-3, {    -0x1.fd5ba9aac2f6ep-4,    0x1.cd37686760c17p-59 }, 1 }, // atan(-0.125) == -0.12435499454676143503
    {    -0x1.0000000000000p-4, {    -0x1.ff55bb72cfdeap-5,    0x1.c934d86d23f1dp-60 }, 1 }, // atan(-0.0625) == -0.062418809995957348474
    {                 0x0.0p+0, {                 0x0.0p+0,                 0x0.0p+0 }, 1 }, // atan(0.0) == 0.0
    {     0x1.0000000000000p-4, {     0x1.ff55bb72cfdeap-5,   -0x1.c934d86d23f1dp-60 }, 1 }, // atan(0.0625) == 0.062418809995957348474
    {     0x1.0000000000000p-3, {     0x1.fd5ba9aac2f6ep-4,   -0x1.cd37686760c17p-59 }, 1 }, // atan(0.125) == 0.12435499454676143503
    {     0x1.8000000000000p-3, {     0x1.7b97b4bce5b02p-3,    0x1.347b0b4f881cap-58 }, 1 }, // atan(0.1875) == 0.18534794999569476489
    {     0x1.0000000000000p-2, {     0x1.f5b75f92c80ddp-3,    0x1.8ab6e3cf7afbdp-57 }, 1 }, // atan(0.25) == 0.24497866312686415417
    {     0x1.4000000000000p-2, {     0x1.362773707ebccp-2,   -0x1.963a544b672d8p-57 }, 1 }, // atan(0.3125) == 0.30288486837497140556
    {     0x1.8000000000000p-2, {     0x1.6f61941e4def1p-2,   -0x1.c63aae6f6e918p-56 }, 1 }, // atan(0.375) == 0.3587706702705722204
    {     0x1.c000000000000p-2, {     0x1.a64eec3cc23fdp-2,   -0x1.24dec1b50b7ffp-56 }, 1 }, // atan(0.4375) == 0.4124104415973873069
    {     0x1.0000000000000p-1, {     0x1.dac670561bb4fp-2,    0x1.a2b7f222f65e2p-56 }, 1 }, // atan(0.5) == 0.46364760900080611621
    {     0x1.2000000000000p-1, {     0x1.0657e94db30d0p-1,   -0x1.d5b495f6349e6p-56 }, 1 }, // atan(0.5625) == 0.51238946031073770667
    {     0x1.4000000000000p-1, {     0x1.1e00babdefeb4p-1,   -0x1.928df287a668fp-58 }, 1 }, // atan(0.625) == 0.55859931534356243597
    {     0x1.6000000000000p-1, {     0x1.345f01cce37bbp-1,    0x1.1021137c71102p-55 }, 1 }, // atan(0.6875) == 0.60228734613496418168
    {     0x1.8000000000000p-1, {     0x1.4978fa3269ee1p-1,    0x1.2419a87f2a458p-56 }, 1 }, // atan(0.75) == 0.6435011087932843868
    {     0x1.a000000000000p-1, {     0x1.5d58987169b18p-1,    0x1.0028e4bc5e7cap-57 }, 1 }, // atan(0.8125) == 0.68231655487474807826
    {     0x1.c000000000000p-1, {     0x1.700a7c5784634p-1,   -0x1.8c34d25aadef6p-56 }, 1 }, // atan(0.875) == 0.71882999962162450542
    {     0x1.e000000000000p-1, {     0x1.819d0b7158a4dp-1,   -0x1.bf76229d3b917p-56 }, 1 }, // atan(0.9375) == 0.75315128096219438952
    {     0x1.0000000000000p+0, {     0x1.921fb54442d18p-1,    0x1.1a62633145c07p-55 }, 1 }, // atan(1.0) == 0.78539816339744830962
    {     0x1.199999999999ap+0, {     0x1.aa7c8545183cdp-1,    0x1.13c7f9e32346bp-56 }, 1 }, // atan(1.1) == 0.83298126667443174561
    {     0x1.60ccccccccccdp+0, {     0x1.e2db51810d518p-1,    0x1.2cc836aa3dc08p-55 }, 1 }, // atan(1.378125) == 0.94307951641409019025
    {     0x1.a800000000000p+0, {     0x1.07113c6a93a21p+0,    0x1.c2bc4d3a3e69fp-56 }, 1 }, // atan(1.65625) == 1.027606750507068758
    {     0x1.ef33333333334p+0, {     0x1.17facdd16b8c3p+0,   -0x1.d29cce4be0e46p-54 }, 1 }, // atan(1.9343750000000002) == 1.0936707149772223567
    {     0x1.1b33333333334p+1, {     0x1.2573dd70e37b6p+0,    0x1.5a8de2893e80ap-58 }, 1 }, // atan(2.2125000000000004) == 1.1462992096526085686
    {     0x1.3eccccccccccdp+1, {     0x1.3061d2904dfd5p+0,   -0x1.996b18d3bbb7fp-54 }, 1 }, // atan(2.490625) == 1.1889926531130089682
    {     0x1.6266666666667p+1, {     0x1.39654d4406185p+0,   -0x1.360b7c6780d00p-56 }, 1 }, // atan(2.7687500000000003) == 1.2242019930909873003
    {     0x1.8600000000000p+1, {     0x1.40f066c808d09p+0,    0x1.7864728af14dfp-54 }, 1 }, // atan(3.046875) == 1.2536682356229128227
    {     0x1.a99999999999ap+1, {     0x1.4755992dd7141p+0,   -0x1.f72acb11d6da2p-54 }, 1 }, // atan(3.325) == 1.2786498772539546273
    {     0x1.cd33333333334p+1, {     0x1.4cd1980df35d9p+0,   -0x1.6246583f43738p-55 }, 1 }, // atan(3.6031250000000004) == 1.3000731500682063018
    {     0x1.f0ccccccccccdp+1, {     0x1.5191d8f34d801p+0,    0x1.6e7e1d22e9713p-54 }, 1 }, // atan(3.88125) == 1.3186317056656665332
    {     0x1.0a33333333334p+2, {     0x1.55b8f68b1bdb4p+0,   -0x1.d22266036e5aap-55 }, 1 }, // atan(4.159375000000001) == 1.3348535623189094529
    {     0x1.1c00000000000p+2, {     0x1.5961aeac184b3p+0,   -0x1.ae4b95d52e176p-54 }, 1 }, // atan(4.4375) == 1.3491467638162190256
    {     0x1.2dccccccccccdp+2, {     0x1.5ca0f56f2f422p+0,    0x1.771f15abf1a40p-54 }, 1 }, // atan(4.715625) == 1.3618310352751526718
    {     0x1.3f9999999999ap+2, {     0x1.5f876b7be0801p+0,    0x1.ef42ff94e8697p-54 }, 1 }, // atan(4.99375) == 1.3731600930627795262
    {     0x1.5166666666666p+2, {     0x1.62226a075653dp+0,   -0x1.d7b24c3376485p-56 }, 1 }, // atan(5.271875) == 1.3833376186287999776
    {     0x1.6333333333334p+2, {     0x1.647cc59cecbcep+0,   -0x1.2ee378533bc81p-54 }, 1 }, // atan(5.550000000000001) == 1.3925288684956628647
    {     0x1.7500000000000p+2, {     0x1.669f5db2677f4p+0,    0x1.09e0423859928p-55 }, 1 }, // atan(5.828125) == 1.4008692322308862476
    {     0x1.86ccccccccccep+2, {     0x1.689187e4a7e1dp+0,    0x1.6be3c8550a00cp-56 }, 1 }, // atan(6.106250000000001) == 1.4084706242791818129
    {     0x1.989999999999ap+2, {     0x1.6a59610cc6e8ap+0,   -0x1.436ca4f84d4e5p-56 }, 1 }, // atan(6.384375) == 1.4154263168519798202
    {     0x1.aa66666666666p+2, {     0x1.6bfc0b42e1193p+0,   -0x1.d6af08b1e2a52p-54 }, 1 }, // atan(6.6625) == 1.4218146360663907003
    {     0x1.bc33333333334p+2, {     0x1.6d7dddccbc5bcp+0,   -0x1.81392cc2ec04fp-54 }, 1 }, // atan(6.940625000000001) == 1.4277018189280700486
    {     0x1.ce00000000000p+2, {     0x1.6ee28a88f90e7p+0,   -0x1.1809fcbb2ab30p-54 }, 1 }, // atan(7.21875) == 1.4331442436605869532
    {     0x1.dfccccccccccep+2, {     0x1.702d3b6a8c905p+0,    0x1.61212c479bd16p-55 }, 1 }, // atan(7.496875000000001) == 1.4381901869897444729
    {     0x1.f19999999999ap+2, {     0x1.7160a9e6f2a12p+0,    0x1.58de5ef1e91e0p-54 }, 1 }, // atan(7.775) == 1.442881220706685305
    {     0x1.01b3333333333p+3, {     0x1.727f31bbb3995p+0,    0x1.5dab3f57784acp-56 }, 1 }, // atan(8.053125) == 1.4472533305412061034
    {     0x1.0a9999999999ap+3, {     0x1.738ae01592751p+0,    0x1.a783d4b93cc0ep-55 }, 1 }, // atan(8.33125) == 1.4513378193537003662
    {     0x1.1380000000000p+3, {     0x1.74857fe2337e8p+0,   -0x1.1851362430156p-56 }, 1 }, // atan(8.609375) == 1.4551620414017580733
    {     0x1.1c66666666667p+3, {     0x1.7570a3e5083a7p+0,    0x1.55b1c5baf3557p-55 }, 1 }, // atan(8.887500000000001) == 1.4587500032577993918
    {     0x1.254cccccccccdp+3, {     0x1.764daf04c3b97p+0,   -0x1.fa70c9ace0d8fp-55 }, 1 }, // atan(9.165625) == 1.4621228586799809863
    {     0x1.2e33333333333p+3, {     0x1.771ddb2c0f5eap+0,    0x1.2c881dfb17a7dp-54 }, 1 }, // atan(9.44375) == 1.4652993185585452925
    {     0x1.371999999999ap+3, {     0x1.77e23f0438b3dp+0,   -0x1.745f27245de79p-54 }, 1 }, // atan(9.721875) == 1.4682959924036388691
    {     0x1.4000000000000p+3, {     0x1.789bd2c160054p+0,   -0x1.f45503ccad255p-54 }, 1 }, // atan(10.0) == 1.4711276743037345919
};

void Test_atan_approx(void)
{
    for (int i = 0; i < _countof(s_atan_approx_tests); i++)
    {
        double x = s_atan_approx_tests[i].x;
        double expected = s_atan_approx_tests[i].expected.rounded;
        double z = atan(x);
        int64_t error = abs(ulp_error_precise(&s_atan_approx_tests[i].expected, z));
        ok(error <= s_atan_approx_tests[i].max_error,
            "atan(%.17e) = %.17e, expected %.17e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_atan_approx_tests[i].max_error);
    }
}

#if defined(HAS_ATANF)

// These are expected to match exactly
static TESTENTRY_DBL s_atanf_exact_tests[] =
{
    { 0x00000000 /*  0.000000 */, 0x00000000 /*  0.000000 */ },
    { 0x80000000 /* -0.000000 */, 0x00000000 /*  0.000000 */ },
    { 0x7f800000 /*  1.#INF00 */, 0x00000000 /*  0.000000 */ },
    { 0x7f800001 /*  1.#SNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0x7fBFffff /*  1.#SNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0x7fC00000 /*  1.#QNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0x7fC80001 /*  1.#QNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0x7fFfffff /*  1.#QNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0xff800000 /* -1.#INF00 */, 0x00000000 /*  0.000000 */ },
    { 0xff800001 /* -1.#SNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0xffBfffff /* -1.#SNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0xffC00000 /* -1.#IND00 */, 0x00000000 /*  0.000000 */ },
    { 0xfff80001 /* -1.#QNAN0 */, 0x00000000 /*  0.000000 */ },
    { 0xffffffff /* -1.#QNAN0 */, 0x00000000 /*  0.000000 */ },
};

void Test_atanf_exact(void)
{
    for (int i = 0; i < _countof(s_atanf_exact_tests); i++)
    {
        float x = u64_to_dbl(s_atanf_exact_tests[i].x);
        float z = atanf(x);
        ok_eq_flt_exact("atanf", s_atanf_exact_tests[i].x, z, s_atanf_exact_tests[i].result);
    }
}

#endif // defined(HAS_ATANF)

#if defined(HAS_ATANF) || defined(HAS_LIBM_SSE2)

static TESTENTRY_DBL_APPROX s_atanf_approx_tests[] =
{
//  {    x,                     {    y_rounded,               y_difference           } }
    {    -0x1.4000000000000p+3, {    -0x1.789bd2c160054p+0,    0x1.f45503ccad255p-54 }, 1 }, // atanf(-10.0) == -1.4711276743037345919
    {    -0x1.36e6660000000p+3, {    -0x1.77ddf47833756p+0,    0x1.fb66d1f9dffeap-55 }, 1 }, // atanf(-9.715624809265137) == -1.4682305139026161083
    {    -0x1.2dcccc0000000p+3, {    -0x1.7714c2a62c643p+0,   -0x1.4dc04f47c52d8p-54 }, 1 }, // atanf(-9.431249618530273) == -1.4651605277725970491
    {    -0x1.24b3340000000p+3, {    -0x1.763f331e9fa45p+0,   -0x1.40f0d0a10763cp-54 }, 1 }, // atanf(-9.146875381469727) == -1.461901850677933837
    {    -0x1.1b999a0000000p+3, {    -0x1.755c19a3be84ap+0,   -0x1.b008aaa10184dp-55 }, 1 }, // atanf(-8.862500190734863) == -1.4584365868345395192
    {    -0x1.1280000000000p+3, {    -0x1.746a2395437b5p+0,    0x1.331b873ab986dp-55 }, 1 }, // atanf(-8.578125) == -1.4547445525563322488
    {    -0x1.0966660000000p+3, {    -0x1.7367d0b8a57f2p+0,   -0x1.664fbc5079424p-55 }, 1 }, // atanf(-8.293749809265137) == -1.4508028460309075169
    {    -0x1.004ccc0000000p+3, {    -0x1.72536b90ed833p+0,   -0x1.cf64242c4e44bp-54 }, 1 }, // atanf(-8.009374618530273) == -1.4465853909328075694
    {    -0x1.ee66660000000p+2, {    -0x1.712affff54d56p+0,    0x1.aeb580652a527p-55 }, 1 }, // atanf(-7.724999904632568) == -1.4420623777740124249
    {    -0x1.dc33340000000p+2, {    -0x1.6fec4f49258c2p+0,   -0x1.c5ee54df8205fp-55 }, 1 }, // atanf(-7.440625190734863) == -1.4371995500164734198
    {    -0x1.ca00000000000p+2, {    -0x1.6e94c20af4b20p+0,   -0x1.7a0fa624e176cp-56 }, 1 }, // atanf(-7.15625) == -1.4319573666331919731
    {    -0x1.b7cccc0000000p+2, {    -0x1.6d2156e6baed7p+0,    0x1.544417c57ecfep-55 }, 1 }, // atanf(-6.871874809265137) == -1.4262899697595707491
    {    -0x1.a5999a0000000p+2, {    -0x1.6b8e8c4a2cff7p+0,   -0x1.0daa06edbba75p-54 }, 1 }, // atanf(-6.587500095367432) == -1.4201438599675365067
    {    -0x1.9366660000000p+2, {    -0x1.69d84438d1377p+0,   -0x1.fc32985124147p-57 }, 1 }, // atanf(-6.303124904632568) == -1.4134562147821421312
    {    -0x1.8133340000000p+2, {    -0x1.67f9a2839e992p+0,    0x1.45fc31d58572ap-56 }, 1 }, // atanf(-6.018750190734863) == -1.4061528750740745864
    {    -0x1.6f00000000000p+2, {    -0x1.65ecde7494896p+0,    0x1.25d613afe5c17p-56 }, 1 }, // atanf(-5.734375) == -1.3981455835933380545
    {    -0x1.5ccccc0000000p+2, {    -0x1.63ab0a4e38354p+0,    0x1.25ee66ebee77bp-54 }, 1 }, // atanf(-5.449999809265137) == -1.3893286171880462805
    {    -0x1.4a999a0000000p+2, {    -0x1.612bc73045e72p+0,    0x1.90c09eba8fd11p-54 }, 1 }, // atanf(-5.165625095367432) == -1.3795742504934448666
    {    -0x1.3866660000000p+2, {    -0x1.5e64e056212aep+0,   -0x1.bd4b719ef955cp-54 }, 1 }, // atanf(-4.881249904632568) == -1.368726750400280786
    {    -0x1.2633340000000p+2, {    -0x1.5b49c7a131efep+0,   -0x1.382e5f4673605p-55 }, 1 }, // atanf(-4.596875190734863) == -1.3565945404570239124
    {    -0x1.1400000000000p+2, {    -0x1.57cade57dba51p+0,    0x1.8b8666c0ed546p-60 }, 1 }, // atanf(-4.3125) == -1.3429392780777968928
    {    -0x1.01cccc0000000p+2, {    -0x1.53d47f0ee937fp+0,    0x1.58e8a7e5f6676p-55 }, 1 }, // atanf(-4.028124809265137) == -1.3274611865428764438
    {    -0x1.df33340000000p+1, {    -0x1.4f4da2685aa4bp+0,   -0x1.10f9b2efbb036p-54 }, 1 }, // atanf(-3.7437500953674316) == -1.3097783570070927232
    {    -0x1.bacccc0000000p+1, {    -0x1.4a15f23f6bdc6p+0,    0x1.47955a06330b8p-55 }, 1 }, // atanf(-3.4593749046325684) == -1.2893973736607775216
    {    -0x1.9666660000000p+1, {    -0x1.440309073d564p+0,   -0x1.ef23758257b96p-56 }, 1 }, // atanf(-3.174999952316284) == -1.2656713144945906093
    {    -0x1.7200000000000p+1, {    -0x1.3cdc609d20e5bp+0,   -0x1.e158a27cb7c2dp-54 }, 1 }, // atanf(-2.890625) == -1.2377376922239794399
    {    -0x1.4d999a0000000p+1, {    -0x1.345546fcadaf0p+0,   -0x1.8ba3c61ad88dep-58 }, 1 }, // atanf(-2.606250047683716) == -1.2044262282267332918
    {    -0x1.2933340000000p+1, {    -0x1.2a03b62463562p+0,    0x1.efb1ba5596d7fp-54 }, 1 }, // atanf(-2.3218750953674316) == -1.1641191328847856381
    {    -0x1.04cccc0000000p+1, {    -0x1.1d52583130f77p+0,    0x1.364f74329c885p-55 }, 1 }, // atanf(-2.0374999046325684) == -1.11453772736510156
    {    -0x1.c0cccc0000000p+0, {    -0x1.0d6b4ac6534a9p+0,    0x1.d67e65e3f9d00p-56 }, 1 }, // atanf(-1.7531249523162842) == -1.0524183973496212563
    {    -0x1.7800000000000p+0, {    -0x1.f232073aeb172p-1,    0x1.5f5b3a2cdfc2cp-55 }, 1 }, // atanf(-1.46875) == -0.97303793520181454745
    {    -0x1.2f33340000000p+0, {    -0x1.bd3cd9df2f465p-1,   -0x1.aeff310e36f95p-58 }, 1 }, // atanf(-1.1843750476837158) == -0.86960488175794792871
    {    -0x1.cccccc0000000p-1, {    -0x1.77338a0f3a0bcp-1,    0x1.d0675049d2006p-55 }, 1 }, // atanf(-0.8999999761581421) == -0.73281508861420924755
    {    -0x1.0000000000000p+0, {    -0x1.921fb54442d18p-1,   -0x1.1a62633145c07p-55 }, 1 }, // atanf(-1.0) == -0.78539816339744830962
    {    -0x1.e000000000000p-1, {    -0x1.819d0b7158a4dp-1,    0x1.bf76229d3b917p-56 }, 1 }, // atanf(-0.9375) == -0.75315128096219438952
    {    -0x1.c000000000000p-1, {    -0x1.700a7c5784634p-1,    0x1.8c34d25aadef6p-56 }, 1 }, // atanf(-0.875) == -0.71882999962162450542
    {    -0x1.a000000000000p-1, {    -0x1.5d58987169b18p-1,   -0x1.0028e4bc5e7cap-57 }, 1 }, // atanf(-0.8125) == -0.68231655487474807826
    {    -0x1.8000000000000p-1, {    -0x1.4978fa3269ee1p-1,   -0x1.2419a87f2a458p-56 }, 1 }, // atanf(-0.75) == -0.6435011087932843868
    {    -0x1.6000000000000p-1, {    -0x1.345f01cce37bbp-1,   -0x1.1021137c71102p-55 }, 1 }, // atanf(-0.6875) == -0.60228734613496418168
    {    -0x1.4000000000000p-1, {    -0x1.1e00babdefeb4p-1,    0x1.928df287a668fp-58 }, 1 }, // atanf(-0.625) == -0.55859931534356243597
    {    -0x1.2000000000000p-1, {    -0x1.0657e94db30d0p-1,    0x1.d5b495f6349e6p-56 }, 1 }, // atanf(-0.5625) == -0.51238946031073770667
    {    -0x1.0000000000000p-1, {    -0x1.dac670561bb4fp-2,   -0x1.a2b7f222f65e2p-56 }, 1 }, // atanf(-0.5) == -0.46364760900080611621
    {    -0x1.c000000000000p-2, {    -0x1.a64eec3cc23fdp-2,    0x1.24dec1b50b7ffp-56 }, 1 }, // atanf(-0.4375) == -0.4124104415973873069
    {    -0x1.8000000000000p-2, {    -0x1.6f61941e4def1p-2,    0x1.c63aae6f6e918p-56 }, 1 }, // atanf(-0.375) == -0.3587706702705722204
    {    -0x1.4000000000000p-2, {    -0x1.362773707ebccp-2,    0x1.963a544b672d8p-57 }, 1 }, // atanf(-0.3125) == -0.30288486837497140556
    {    -0x1.0000000000000p-2, {    -0x1.f5b75f92c80ddp-3,   -0x1.8ab6e3cf7afbdp-57 }, 1 }, // atanf(-0.25) == -0.24497866312686415417
    {    -0x1.8000000000000p-3, {    -0x1.7b97b4bce5b02p-3,   -0x1.347b0b4f881cap-58 }, 1 }, // atanf(-0.1875) == -0.18534794999569476489
    {    -0x1.0000000000000p-3, {    -0x1.fd5ba9aac2f6ep-4,    0x1.cd37686760c17p-59 }, 1 }, // atanf(-0.125) == -0.12435499454676143503
    {    -0x1.0000000000000p-4, {    -0x1.ff55bb72cfdeap-5,    0x1.c934d86d23f1dp-60 }, 1 }, // atanf(-0.0625) == -0.062418809995957348474
    {                 0x0.0p+0, {                 0x0.0p+0,                 0x0.0p+0 }, 1 }, // atanf(0.0) == 0.0
    {     0x1.0000000000000p-4, {     0x1.ff55bb72cfdeap-5,   -0x1.c934d86d23f1dp-60 }, 1 }, // atanf(0.0625) == 0.062418809995957348474
    {     0x1.0000000000000p-3, {     0x1.fd5ba9aac2f6ep-4,   -0x1.cd37686760c17p-59 }, 1 }, // atanf(0.125) == 0.12435499454676143503
    {     0x1.8000000000000p-3, {     0x1.7b97b4bce5b02p-3,    0x1.347b0b4f881cap-58 }, 1 }, // atanf(0.1875) == 0.18534794999569476489
    {     0x1.0000000000000p-2, {     0x1.f5b75f92c80ddp-3,    0x1.8ab6e3cf7afbdp-57 }, 1 }, // atanf(0.25) == 0.24497866312686415417
    {     0x1.4000000000000p-2, {     0x1.362773707ebccp-2,   -0x1.963a544b672d8p-57 }, 1 }, // atanf(0.3125) == 0.30288486837497140556
    {     0x1.8000000000000p-2, {     0x1.6f61941e4def1p-2,   -0x1.c63aae6f6e918p-56 }, 1 }, // atanf(0.375) == 0.3587706702705722204
    {     0x1.c000000000000p-2, {     0x1.a64eec3cc23fdp-2,   -0x1.24dec1b50b7ffp-56 }, 1 }, // atanf(0.4375) == 0.4124104415973873069
    {     0x1.0000000000000p-1, {     0x1.dac670561bb4fp-2,    0x1.a2b7f222f65e2p-56 }, 1 }, // atanf(0.5) == 0.46364760900080611621
    {     0x1.2000000000000p-1, {     0x1.0657e94db30d0p-1,   -0x1.d5b495f6349e6p-56 }, 1 }, // atanf(0.5625) == 0.51238946031073770667
    {     0x1.4000000000000p-1, {     0x1.1e00babdefeb4p-1,   -0x1.928df287a668fp-58 }, 1 }, // atanf(0.625) == 0.55859931534356243597
    {     0x1.6000000000000p-1, {     0x1.345f01cce37bbp-1,    0x1.1021137c71102p-55 }, 1 }, // atanf(0.6875) == 0.60228734613496418168
    {     0x1.8000000000000p-1, {     0x1.4978fa3269ee1p-1,    0x1.2419a87f2a458p-56 }, 1 }, // atanf(0.75) == 0.6435011087932843868
    {     0x1.a000000000000p-1, {     0x1.5d58987169b18p-1,    0x1.0028e4bc5e7cap-57 }, 1 }, // atanf(0.8125) == 0.68231655487474807826
    {     0x1.c000000000000p-1, {     0x1.700a7c5784634p-1,   -0x1.8c34d25aadef6p-56 }, 1 }, // atanf(0.875) == 0.71882999962162450542
    {     0x1.e000000000000p-1, {     0x1.819d0b7158a4dp-1,   -0x1.bf76229d3b917p-56 }, 1 }, // atanf(0.9375) == 0.75315128096219438952
    {     0x1.0000000000000p+0, {     0x1.921fb54442d18p-1,    0x1.1a62633145c07p-55 }, 1 }, // atanf(1.0) == 0.78539816339744830962
    {     0x1.19999a0000000p+0, {     0x1.aa7c85a1c3ad1p-1,    0x1.a54455aa8821ap-55 }, 1 }, // atanf(1.100000023841858) == 0.83298127746260257747
    {     0x1.60cccc0000000p+0, {     0x1.e2db50f3c5e72p-1,    0x1.e2d71bc0715bcp-56 }, 1 }, // atanf(1.3781249523162842) == 0.94307949996705378434
    {     0x1.a800000000000p+0, {     0x1.07113c6a93a21p+0,    0x1.c2bc4d3a3e69fp-56 }, 1 }, // atanf(1.65625) == 1.027606750507068758
    {     0x1.ef33340000000p+0, {     0x1.17facdfc9c42ep+0,    0x1.37777adc68236p-55 }, 1 }, // atanf(1.9343750476837158) == 1.0936707250332449508
    {     0x1.1b33340000000p+1, {     0x1.2573ddb65e8f0p+0,   -0x1.6bba4d536c953p-55 }, 1 }, // atanf(2.2125000953674316) == 1.1462992258298605069
    {     0x1.3ecccc0000000p+1, {     0x1.3061d25770edep+0,    0x1.7d8ee902b84dap-56 }, 1 }, // atanf(2.4906249046325684) == 1.188992639873439859
    {     0x1.6266660000000p+1, {     0x1.39654d2c6422ep+0,   -0x1.24c47175ad213p-54 }, 1 }, // atanf(2.768749952316284) == 1.2242019875885818334
    {     0x1.8600000000000p+1, {     0x1.40f066c808d09p+0,    0x1.7864728af14dfp-54 }, 1 }, // atanf(3.046875) == 1.2536682356229128227
    {     0x1.a9999a0000000p+1, {     0x1.4755993ed3fc6p+0,    0x1.d86da60eb4d96p-59 }, 1 }, // atanf(3.325000047683716) == 1.2786498812092630427
    {     0x1.cd33340000000p+1, {     0x1.4cd1982b3e900p+0,    0x1.0063ad5853019p-54 }, 1 }, // atanf(3.6031250953674316) == 1.3000731568886863544
    {     0x1.f0cccc0000000p+1, {     0x1.5191d8d9ce0d3p+0,   -0x1.cb7d5e80fd642p-54 }, 1 }, // atanf(3.8812499046325684) == 1.3186316997289863176
    {     0x1.0a33340000000p+2, {     0x1.55b8f6b7df73cp+0,   -0x1.05e73f9135c77p-55 }, 1 }, // atanf(4.159375190734863) == 1.3348535727413510515
    {     0x1.1c00000000000p+2, {     0x1.5961aeac184b3p+0,   -0x1.ae4b95d52e176p-54 }, 1 }, // atanf(4.4375) == 1.3491467638162190256
    {     0x1.2dcccc0000000p+2, {     0x1.5ca0f54bee3fep+0,   -0x1.3d4aacbdcc59bp-54 }, 1 }, // atanf(4.715624809265137) == 1.3618310270669548445
    {     0x1.3f999a0000000p+2, {     0x1.5f876b8bab326p+0,    0x1.e4cb4e4942a1cp-55 }, 1 }, // atanf(4.993750095367432) == 1.3731600967395905492
    {     0x1.5166660000000p+2, {     0x1.622269f91c82dp+0,    0x1.650c138dcba9cp-55 }, 1 }, // atanf(5.271874904632568) == 1.3833376153165873155
    {     0x1.6333340000000p+2, {     0x1.647cc5b6af096p+0,    0x1.812407f7474c2p-55 }, 1 }, // atanf(5.550000190734863) == 1.3925288744931428182
    {     0x1.7500000000000p+2, {     0x1.669f5db2677f4p+0,    0x1.09e0423859928p-55 }, 1 }, // atanf(5.828125) == 1.4008692322308862476
    {     0x1.86cccc0000000p+2, {     0x1.689187cf42541p+0,   -0x1.b3bb04fd1f97cp-55 }, 1 }, // atanf(6.106249809265137) == 1.4084706192973756672
    {     0x1.98999a0000000p+2, {     0x1.6a59611695da1p+0,   -0x1.81800de1010a7p-58 }, 1 }, // atanf(6.384375095367432) == 1.4154263191356692922
    {     0x1.aa66660000000p+2, {     0x1.6bfc0b39dae52p+0,   -0x1.77411a7979317p-55 }, 1 }, // atanf(6.662499904632568) == 1.4218146339652730374
    {     0x1.bc33340000000p+2, {     0x1.6d7ddddd65440p+0,   -0x1.335d47af28ccep-54 }, 1 }, // atanf(6.940625190734863) == 1.4277018228069805916
    {     0x1.ce00000000000p+2, {     0x1.6ee28a88f90e7p+0,   -0x1.1809fcbb2ab30p-54 }, 1 }, // atanf(7.21875) == 1.4331442436605869532
    {     0x1.dfcccc0000000p+2, {     0x1.702d3b5c3a6a4p+0,   -0x1.f9e29b0d45b06p-54 }, 1 }, // atanf(7.496874809265137) == 1.438190183655401523
    {     0x1.f1999a0000000p+2, {     0x1.7160a9ed9d004p+0,    0x1.b4a87b9f01e24p-55 }, 1 }, // atanf(7.775000095367432) == 1.4428812222586211907
    {     0x1.01b3340000000p+3, {     0x1.727f31d494cedp+0,   -0x1.3ffba726158e1p-54 }, 1 }, // atanf(8.053125381469727) == 1.4472533363339678408
    {     0x1.0a999a0000000p+3, {     0x1.738ae02134f47p+0,   -0x1.2adfe2f905156p-57 }, 1 }, // atanf(8.331250190734863) == 1.4513378220626280609
    {     0x1.1380000000000p+3, {     0x1.74857fe2337e8p+0,   -0x1.1851362430156p-56 }, 1 }, // atanf(8.609375) == 1.4551620414017580733
    {     0x1.1c66660000000p+3, {     0x1.7570a3daca624p+0,   -0x1.774db1eebb5ddp-54 }, 1 }, // atanf(8.887499809265137) == 1.4587500008732456077
    {     0x1.254ccc0000000p+3, {     0x1.764daef17dc0bp+0,    0x1.ea48234a1fe8dp-55 }, 1 }, // atanf(9.165624618530273) == 1.4621228541925599929
    {     0x1.2e33340000000p+3, {     0x1.771ddb3e3a2d7p+0,    0x1.7daf46f8a013cp-54 }, 1 }, // atanf(9.443750381469727) == 1.465299322788430419
    {     0x1.37199a0000000p+3, {     0x1.77e23f0ccc54ep+0,   -0x1.b76ae4bbc0fabp-54 }, 1 }, // atanf(9.721875190734863) == 1.4682959944005519339
    {     0x1.4000000000000p+3, {     0x1.789bd2c160054p+0,   -0x1.f45503ccad255p-54 }, 1 }, // atanf(10.0) == 1.4711276743037345919
};

#endif // defined(HAS_ATANF) || defined(HAS_LIBM_SSE2)

#if defined(HAS_ATANF)

void Test_atanf_approx(void)
{
    for (int i = 0; i < _countof(s_atanf_approx_tests); i++)
    {
        float x = s_atanf_approx_tests[i].x;
        float expected = s_atanf_approx_tests[i].expected.rounded;
        float z = atanf(x);
        int64_t error = abs(ulp_error_flt(expected, z));
        ok(error <= s_atan_approx_tests[i].max_error,
            "atan(%.6e) = %.7e, expected %.7e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_atan_approx_tests[i].max_error);
    }
}

#endif // defined(HAS_ATANF)

#if defined(HAS_LIBM_SSE2)

__ATTRIBUTE_SSE2__ __m128d __libm_sse2_atan(__m128d Xmm0);

__ATTRIBUTE_SSE2__
void Test_libm_sse2_atan(void)
{
    int i;
    for (i = 0; i < _countof(s_atan_approx_tests); i++)
    {
        double x = s_atan_approx_tests[i].x;
        double expected = s_atan_approx_tests[i].expected.rounded;
        __m128d xmm0 = _mm_set_sd(x);
        __m128d xmm1 = __libm_sse2_atan(xmm0);
        double z = _mm_cvtsd_f64(xmm1);
        int64_t error = ulp_error_precise(&s_atan_approx_tests[i].expected, z);
        ok(error <= s_atan_approx_tests[i].max_error,
            "__libm_sse2_atan(%.17e) = %.17e, expected %.17e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_atan_approx_tests[i].max_error);
    }
}

__ATTRIBUTE_SSE2__ __m128 __libm_sse2_atanf(__m128 Xmm0);

__ATTRIBUTE_SSE2__
void Test_libm_sse2_atanf(void)
{
    int i;
    for (i = 0; i < _countof(s_atanf_approx_tests); i++)
    {
        float x = s_atanf_approx_tests[i].x;
        float expected = s_atanf_approx_tests[i].expected.rounded;
        __m128 xmm0 = _mm_set_ps1(x);
        __m128 xmm1 = __libm_sse2_atanf(xmm0);
        float z = _mm_cvtss_f32(xmm1);
        int64_t error = ulp_error_flt(expected, z);
        ok(error <= s_atanf_approx_tests[i].max_error,
            "__libm_sse2_atanf(%.6e) = %.7e, expected %.7e, error %I64d ULPs, max %u ULPs\n",
            x, z, expected, error, s_atanf_approx_tests[i].max_error);
    }
}

#endif // defined(HAS_LIBM_SSE2)

START_TEST(atan)
{
    Test_atan_exact();
    Test_atan_approx();
#if defined(HAS_ATANF)
    Test_atanf_exact();
    Test_atanf_approx();
#endif
#if defined(HAS_LIBM_SSE2)
    Test_libm_sse2_atan();
    Test_libm_sse2_atanf();
#endif
}
